const express = require('express');
const mysql = require('mysql');
const cors = require('cors');
const app = express();
const jwt = require('jsonwebtoken');
const multer = require('multer');
const redis = require('redis');
const secretKey = 'my_secret_key';
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const svgCaptcha = require('svg-captcha');
const PORT = 3000;
let client;

app.use(express.json()); // 用于解析JSON格式的请求体
app.use(express.urlencoded({ extended: true })); //
app.use(cors());// 允许特定源的跨域请求
app.use('/uploads', express.static('uploads'));

// 创建数据库连接
const connection = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: '123456',
    database: 'only-serve'
});
// 连接到数据库
connection.connect((err) => {
    if (err) {
        console.error('数据库连接失败:', err);
        return;
    }
    console.log('成功连接到数据库');
});

//创建Redis连接
async function connectToRedis() {
    client = redis.createClient({
        url: 'redis://localhost:6379'
    });
    try {
        await client.connect();
        console.log('成功连接到Redis');
    } catch (err) {
        console.error('Redis连接失败:', err);
    }
}
//连接到Redis
connectToRedis();

// 设置Redis中token的过期时间--
async function storeTokenInRedis(token, userId) {
    await client.set(token, userId, {
        EX: 1800
    });
}

//MD5加密函数--
function MD5(password) {
    return crypto.createHash('md5').update(password).digest('hex');
}

//图形验证码--
app.get('/code', (req, res) => {
    const img = svgCaptcha.createMathExpr({
        // size: 6, // 验证码长度
        // ignoreChars: '0o1il', // 验证码字符中排除 0o1i
        mathMin: 1, // 运算中的最小数字
        mathMax: 16, // 运算中的最大数字
        mathOperator: '+-', // 可以是字符串或数组，数组时随机选择一个运算符
        color: true, // 验证码是否有彩色
        noise: 6, // 干扰线数量
        background: 'white', // 背景颜色
        width: 120, // 图片宽度
    })
    res.status(200).json(img);
})

//登录请求接口--
app.post('/login', (req, res) => {
    const { username, password } = req.body;
    if (username == null || password == null) {
        res.status(403).json({ message: '请输入账号或密码' });
    }
    const sqlCheckUsername = 'SELECT * FROM os_users WHERE username = ?';
    connection.query(sqlCheckUsername, [username], (err, results) => {
        if (err) {
            res.status(500).send('查询数据库失败');
            return;
        }
        if (results.length === 0) {
            res.status(404).json({ message: '账号不存在' });
        } else {
            const user = results[0];
            const storedPassword = user.password;
            if (MD5(password) === storedPassword) {
                const token = jwt.sign(
                    {
                        userId: user.id,
                        role: user.role
                    },
                    secretKey);
                storeTokenInRedis(token, user.id)
                res.status(200).json({ message: '登录成功', data: results, token: token });
            } else {
                res.status(401).json({ message: '密码错误' });
            }
        }
    });
});

//退出登录接口--
app.post('/logout', async (req, res) => {
    const authHeader = req.headers.authorization;
    if (!authHeader) {
        return res.status(401).json({ message: '请提供有效的token' });
    }
    const token = authHeader.split(' ')[1];
    try {
        await client.del(token);
        res.status(200).json({ message: '账号已退出' });
    } catch (err) {
        res.status(500).json({ message: '退出登录时发生错误' });
    }
});

// token认证中间件--
async function authenticateToken(req, res, next) {
    // const token = req.headers.authorization;
    const authHeader = req.headers.authorization;
    if (!authHeader) {
        return res.status(401).json({ message: '请提供有效的token' });
    }
    // 分割Authorization头以获取token
    const parts = authHeader.split(' ');
    if (parts.length !== 2 || parts[0] !== 'Bearer') {
        return res.status(401).json({ message: 'Token格式错误' });
    }
    const token = parts[1];
    // console.log(token);
    try {
        const decoded = jwt.verify(token, secretKey);
        const result = await client.get(token);
        if (!result) {
            return res.status(401).json({ message: 'Token无效或已过期' });
        }
        // Token验证成功，更新Redis中的过期时间
        await client.expire(token, 1800);  // 假设我们想要延长半小时的过期时间
        req.user = decoded;
        next();
    } catch (error) {
        return res.status(403).json({ message: 'Token无效' });
    }
}

//用户权限验证--
function isAdmin(req, res, next) {
    authenticateToken(req, res, () => {
        if (req.user.role === 'admin') {
            next();
        } else {
            res.status(400).json({ message: '需要管理员权限' });
        }
    });
}

//允许跨域请求
app.use(function (req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
});

// 数据请求接口--
app.get('/info',isAdmin, authenticateToken, (req, res) => {
    connection.query('SELECT id, image, title, author, press, about, price FROM os_account', (err, results) => {
        if (err) {
            res.status(500).json({ error: '从数据库获取数据时出错' });
            return;
        }
        res.json(results);
    });
});

// 数据搜索接口--
app.get('/search',isAdmin, authenticateToken, (req, res) => {
    const keyword = req.query.keyword;
    const query = `SELECT * FROM os_account WHERE title LIKE ? OR id LIKE ? OR author LIKE ? OR press LIKE ?`;
    const searchKeyword = `%${keyword}%`;
    if (req.query.keyword === '') {
        res.status(400).json({ message: '请输入搜索关键字' });
    } else {
        connection.query(query, [searchKeyword,searchKeyword,searchKeyword,searchKeyword], (error, results) => {
            if (error) {
                res.status(500).json({ error: 'Error' });
                return;
            }
            res.json(results);
        });
    }
});

//数据添加接口--
app.post('/add',isAdmin, authenticateToken, (req, res) => {
    const { image,title,author,press,about,price } = req.body;
    const sqlInsert = 'INSERT INTO os_account (image,title,author,press,about,price) VALUES (?, ?, ?, ?, ?, ?)';
    connection.query(sqlInsert, [image,title,author,press,about,price], (err, results) => {
        if (err) {
            res.status(500).json({message:'插入数据库失败'});
            return;
        }
        if (results.affectedRows > 0) {
            res.status(200).json({ message: '添加成功' });
        } else {
            res.status(400).json({ message: '添加失败' });
        }
    });
});

// 数据删除接口--
app.delete('/delete/:id',isAdmin, authenticateToken, (req, res) => {
    const { id } = req.params;
    const sqlSelect = 'SELECT image FROM os_account WHERE id = ?';
    connection.query(sqlSelect, [id], (err, results) => {
        if (err) {
            res.status(500).send('查询数据库失败');
            return;
        }
        if (results.length === 0) {
            res.status(404).json({ message: '未找到数据', id: id });
            return;
        }
        const filename = results[0].image;
        if (filename == '') {
            const sqlDelete = 'DELETE FROM os_account WHERE id = ?';
            connection.query(sqlDelete, [id], (err, results) => {
                if (err) {
                    res.status(500).json({ message: '删除数据库失败' });
                    return;
                }
                if (results.affectedRows > 0) {
                    res.status(200).json({ message: '删除成功' });
                } else {
                    res.status(404).json({ message: '未找到数据', id: id });
                }
            });
            return;
        }
        const parsedUrl = new URL(filename);
        const pathname = parsedUrl.pathname;
        const filePath = path.join(__dirname, 'uploads', path.basename(pathname));
        const sqlDelete = 'DELETE FROM os_account WHERE id = ?';
        connection.query(sqlDelete, [id], (err, results) => {
            if (err) {
                res.status(500).json({ message: '删除数据库失败' });
                return;
            }
            if (results.affectedRows > 0) {
                fs.unlink(filePath, (err) => {
                    res.status(200).json({ message: '删除成功' });
                });
            } else {
                res.status(404).json({ message: '未找到数据', id: id });
            }
        });
    });
});

//数据修改接口--
app.put('/items/:id', authenticateToken, isAdmin, (req, res) => {
    const { id } = req.params;
    const { image,title,author,press,about,price } = req.body;
    const sql = 'UPDATE os_account SET image = ?, title = ?, author = ?, press = ?, about = ? ,price = ? WHERE id = ?';
    connection.query(sql, [image,title,author,press,about,price,id], (err, results) => {
        if (err) {
            res.status(500).send('插入数据库失败');
            return;
        }
        if (results.affectedRows > 0) {
            res.status(200).json({ message: '修改成功' });
        } else {
            res.status(400).json({ message: '修改失败' });
        }
    });
});

//数据总量接口--
app.get('/total',isAdmin, authenticateToken, (req, res) => {
    connection.query('SELECT COUNT(*) AS total FROM os_account', (err, results) => {
        if (err) {
            res.status(500).json({ message: '查询数据库失败' });
            return;
        }
        const total = results[0].total;
        res.json({ total });
    });
});

//用户信息请求接口--
app.get('/userinfo',isAdmin, authenticateToken, (req, res) => {
    connection.query('SELECT id,logintime,loginip,name, username,phone, role FROM os_users', (err, results) => {
        if (err) {
            res.status(500).json({ message: '从数据库获取数据时出错' });
            return;
        }
        res.json(results);
    });
});

//用户信息搜索接口--
app.get('/usersearch',isAdmin, authenticateToken, (req, res) => {
    const keyword = req.query.keyword;
    const query = `
        SELECT * FROM os_users 
        WHERE username LIKE ? 
        OR name LIKE ? 
        OR phone LIKE ?`;
    const searchKeyword = `%${keyword}%`;
    if (req.query.keyword === '') {
        res.status(400).json({ message: '请输入搜索关键字' });
    } else {
        connection.query(query, [searchKeyword, searchKeyword, searchKeyword], (error, results) => {
            if (error) {
                res.status(500).json({ error: 'Error' });
                return;
            }
            res.json(results);
        });
    }
});

//用户信息添加接口--
app.post('/useradd', authenticateToken, isAdmin, (req, res) => {
    const { name,username, password,phone, role } = req.body;
    const sqlInsert = 'INSERT INTO os_users (name,username, password,phone, role) VALUES (?,?, MD5(?),?,?)';
    connection.query(sqlInsert, [name, username, password, phone, role], (err, results) => {
        if (err) {
            res.status(500).send('插入数据库失败');
            return;
        }
        if (results.affectedRows > 0) {
            res.status(200).json({ message: '添加成功' });
        } else {
            res.status(400).json({ message: '添加失败' });
        }
    });
});

//用户信息编辑接口--
app.put('/useredit/:id', authenticateToken, isAdmin, (req, res) => {
    const { id } = req.params;
    const { name,username, password,phone, role } = req.body;
    const sql = 'UPDATE os_users SET name = ?, username = ?, password = MD5(?),phone = ?, role = ? WHERE id = ?';
    connection.query(sql, [name, username, password, phone, role, id], (err, results) => {
        if (err) {
            res.status(500).send('插入数据库失败');
            return;
        }
        if (results.affectedRows > 0) {
            res.status(200).json({ message: '修改成功' });
        } else {
            res.status(400).json({ message: '修改失败' });
        }
    });
});

// 用户信息删除接口--
app.delete('/userdelete/:id', authenticateToken, isAdmin, (req, res) => {
    const { id } = req.params;
    const sqlDelete = 'DELETE FROM os_users WHERE id = ?';
    connection.query(sqlDelete, [id], (err, results) => {
        if (err) {
            res.status(500).send('删除数据库失败');
            return;
        }
        if (results.affectedRows > 0) {
            res.status(200).json({ message: '删除成功' });
        } else {
            res.status(404).json({ message: '未找到数据', id: id });
        }
    });
});

//用户信息数量接口--
app.get('/usertotal',isAdmin, authenticateToken, (req, res) => {
    connection.query('SELECT COUNT(*) AS total FROM os_users', (err, results) => {
        if (err) {
            res.status(500).json({ error: '查询数据库失败' });
            return;
        }
        const total = results[0].total;
        res.json({ total });
    });
});

//获取登录时间接口--
app.post('/logintime', (req, res) => {
    const { logintime, userip, username } = req.body;
    connection.query('UPDATE os_users SET logintime = ?, loginip = ? WHERE username = ?',
        [logintime, userip, username], (err, results) => {
            if (err) {
                res.status(500).send('插入数据库失败');
                return;
            }
            if (results.affectedRows > 0) {
                res.status(200).json('插入成功');
            } else {
                res.status(404).json('插入失败');
            }
        });
});

//获取登录ip接口--
app.get('/loginip', (req, res) => {
    const loginip = req.headers['x-forwarded-for'] || req.socket.remoteAddress;
    res.json({ loginip });
});

// 设置multer存储配置--
const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, 'uploads/');
    },
    filename: function (req, file, cb) {
        const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
        cb(null, file.fieldname + '-' + uniqueSuffix + '.png');
    }
});
const upload = multer({ storage: storage });

//图片上传接口--
app.post('/upload', upload.single('image'), (req, res) => {
    if (req.file) {
        // 构建图片URL
        const imageUrl = `${req.protocol}://${req.get('host')}/uploads/${req.file.filename}`;
        res.json({ imageUrl });
    } else {
        res.status(400).json({ error: '请选择一个文件上传' });
    }
});

// 删除图片的 API 处理--
app.delete('/deleteimage', (req, res) => {
    const { imageUrl } = req.body;
    const imageFilePath = path.join(__dirname, 'uploads', path.basename(imageUrl));
    fs.unlink(imageFilePath, (err) => {
        if (err) {
            return res.status(500).json({ message: "删除图片失败" });
        }
        res.json({ message: "删除图片成功" });
    });
});

//错误拦截
app.use((err, req, res, next) => {
    console.error(err.stack);
    res.status(500).json({ message: '内部服务器错误' });
});

app.listen(PORT, () => {
    console.log(`服务器运行在 http://localhost:${PORT}`);
});